package ${filePackageName};

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import ${annotationPackage}.SysLog;
import ${commonVoPackage}.FilePart;
import ${commonVoPackage}.RequestParam;
import ${utilsPackage}.BodyReaderRequestWrapper;
import ${utilsPackage}.ConstantUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.catalina.core.ApplicationPart;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Part;
import java.io.IOException;
import java.util.*;

/**
 * 日志切面类
 * @author ${projectAuthor}
 * @version 1.0
 * @date ${nowDate}
 */
@Component
@Aspect
public class LogAspect {

	private Logger logger = LoggerFactory.getLogger(LogAspect.class);

	/**
	 * 环绕切入
	 * @param joinPoint 切入点
	 * @param sysLog 切入对象
	 * @return 数据
	 * @throws Throwable 异常
	 */
	@Around(value = "@annotation(sysLog)")
	public Object logAround(ProceedingJoinPoint joinPoint, SysLog sysLog)
			throws Throwable {
		long start = System.currentTimeMillis();
		// 执行方法体
		Object result = joinPoint.proceed();

		try {
			HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
			RequestParam params = getParams(request);
			long end = System.currentTimeMillis();
			long timeMillis = end - start;
			logger.info("logAround take time = {}, params={}", timeMillis, params.toString());
		}catch (Exception e){
			logger.error("LogAspect logAround error", e);
		}
		return result;
	}

	/**
	 * 后缀异常
	 * @param joinPoint 切入点
	 * @param sysLog 切入对象
	 * @param e 异常对象
	 * @throws Throwable 异常
	 */
	@AfterThrowing(value = "@annotation(sysLog)",throwing = "e")
	public void afterThrowing(JoinPoint joinPoint, SysLog sysLog,Throwable e)
			throws Throwable {
		long start = System.currentTimeMillis();
		try {

			HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
			RequestParam params = getParams(request);

			long end = System.currentTimeMillis();
			long timeMillis = end - start;

			logger.info("afterThrowing take time = {}, params={}, error={}", timeMillis, params.toString(), e.getMessage());
		} catch (Exception e1) {
			logger.error("LogAspect afterThrowing error", e1);
		}
	}

	/**
	 * 获取请求参数
	 * @param request
	 * @return
	 * @throws IOException
	 */
	private RequestParam getParams(HttpServletRequest request) throws IOException {
		RequestParam requestParam = new RequestParam();
		Map<String,Object> headers = new HashMap<>();

		for (int i=0;i<ConstantUtil.PARAM_HEADERS.length;i++){
			String header = request.getHeader(ConstantUtil.PARAM_HEADERS[i]);
			if(ObjectUtil.isNotEmpty(header)){
				headers.put(ConstantUtil.PARAM_HEADERS[i], header);
			}
		}
		requestParam.setHeaders(headers);

		try {
			List<FilePart> fileParts = new ArrayList<>();
			Collection<Part> parts = request.getParts();
			for (Part part:parts){
				if(part instanceof ApplicationPart){
					ApplicationPart part1 = (ApplicationPart) part;
					String name = part1.getName();
					long size = part1.getSize();
					String submittedFileName = part1.getSubmittedFileName();
					String contentType = part1.getContentType();
					if(StrUtil.isNotBlank(submittedFileName)){
						FilePart filePart = new FilePart();
						filePart.setFieldName(name);
						filePart.setSize(size);
						filePart.setContentType(contentType);
						filePart.setOriginFileName(submittedFileName);
						fileParts.add(filePart);
					}
				}
			}
			requestParam.setParts(fileParts);
		} catch (ServletException e) {
			e.printStackTrace();
		}

		Map<String, String[]> params = request.getParameterMap();
		if (params != null && params.size() > 0) {
			Map<String,Object> form = new HashMap<>();
			for (Map.Entry<String, String[]> entry : params.entrySet()) {
				form.put(entry.getKey(), entry.getValue() == null ? "" : entry.getValue()[0]);
			}
			requestParam.setForm(form);
		}

		String body = new BodyReaderRequestWrapper(request).getBodyString(request);
		if (StrUtil.isNotBlank(body)) {
			if(body.indexOf("[")!=-1 && body.indexOf("]")!=-1){
				JSONArray json = JSON.parseArray(body);
				requestParam.setBody(json);
			}else if(body.indexOf("{")!=-1 && body.indexOf("}")!=-1){
				JSONObject json = JSON.parseObject(body);
				requestParam.setBody(json);
			}else {
				requestParam.setBody(body);
			}
		}
		return requestParam;
	}
}
